#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：icon_monitoring_clicker 
@File ：ScreenMonitor.py
@IDE  ：PyCharm 
@Author ：李涵彬
@Date ：2024/3/20 14:12 
"""

import cv2
import numpy as np
import pyautogui
import PIL.ImageGrab
from typing import Tuple, Any, Sequence

from cv2 import Mat
from numpy import ndarray, dtype, generic


class ScreenMonitor:
	def __init__(self, target_image_path: str) -> None:
		# 从指定路径读取目标图像，使用灰度模式读取
		self.target_image = cv2.imread(target_image_path, cv2.IMREAD_GRAYSCALE)
		# 设置模板匹配方法为归一化相关系数法
		self.template_match_method = cv2.TM_CCOEFF_NORMED

	def capture_screen(self) -> np.ndarray:
		"""
		抓取屏幕图像。

		返回值:
		- screen_cv: 从屏幕抓取的图像，格式为OpenCV的BGR图像。
		"""
		# 使用PIL库抓取当前屏幕的图像
		screen = PIL.ImageGrab.grab()
		# 将PIL图像转换为OpenCV格式，以便于后续处理
		screen_cv = cv2.cvtColor(np.array(screen), cv2.COLOR_BGR2GRAY)
		return screen_cv

	def find_target(self, screen: np.ndarray) -> tuple[
		Sequence[int], ndarray | ndarray[Any, dtype[generic | generic]] | Any]:
		"""
		在给定的屏幕图像中查找目标图像的位置，并在原图像上绘制匹配框后返回。

		参数:
		- screen: 待搜索的屏幕图像。

		返回值:
		- target_top_left: 目标图像左上角的坐标，形式为(x, y)。
		- marked_screen: 绘制了匹配框后的屏幕图像。
		"""
		# 使用模板匹配方法在屏幕图像中搜索目标图像
		res = cv2.matchTemplate(screen, self.target_image, self.template_match_method)
		# 寻找匹配结果中的最大值及其位置
		min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

		# 设置一个匹配阈值，比如0.80（根据实际情况调整）
		match_threshold = 0.80
		print(f"max_val: {max_val}")

		if max_val >= match_threshold:
			# 如果匹配度超过阈值，则继续后续操作
			top_left = max_loc
		# ... (计算bottom_right和绘制矩形框的代码保持不变)
		else:
			# 匹配度未达到阈值，返回空坐标和原屏幕图像
			return None, screen.copy()

		# 计算匹配框的右下角坐标
		match_width = self.target_image.shape[1]
		match_height = self.target_image.shape[0]
		bottom_right = (top_left[0] + match_width, top_left[1] + match_height)

		# 在原屏幕图像上绘制匹配框
		marked_screen = cv2.rectangle(screen.copy(), top_left, bottom_right, (0, 255, 0), 2)

		return top_left, marked_screen

	def click_target(self, target_center: Tuple[int, int]) -> None:
		"""
		点击目标中心位置。

		参数:
		- target_center: 目标中心的坐标，为一个包含两个元素的元组，分别代表x和y坐标。
		"""
		pyautogui.click(target_center[0], target_center[1])

	def monitor(self) -> None:
		"""
		监视屏幕并自动点击目标，在屏幕上显示带有匹配框的目标区域。

		该函数没有参数和返回值。
		"""
		while True:
			# 捕获屏幕图像
			screen = self.capture_screen()
			# 在图像中查找目标并绘制匹配框...
			target_top_left, marked_screen = self.find_target(screen)
			if target_top_left:
				target_center = (target_top_left[0] + self.target_image.shape[1] // 2,
								 target_top_left[1] + self.target_image.shape[0] // 2)
				self.click_target(target_center)

			# 显示带有匹配框的屏幕图像(取消注释即可)
			# cv2.imshow("Screen Monitor", marked_screen)

			# 等待用户按键,按下'q'键时退出程序
			key = cv2.waitKey(1)
			if key == ord('q'):
				break

		cv2.destroyAllWindows()


if __name__ == "__main__":
	monitor = ScreenMonitor("../data/picture/target_image.jpg")
	monitor.monitor()
